/** Import everything needed **/
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.io.Serializable;

/**
 * HW 12b & 13b, "PlayingField"<br><br>
 * 
 * This class represents the main field (board) for the Tetris game. 
 * It stores the current state of the settled pieces, 
 * and also stores the information about the current level,
 *  score, and the comboCount (for combos).
 * It includes methods to check various conditions for the game as well.  
 * 
 * @author Hyun Seo Chung
 * @version 1.0 04/21/12
 */
public class PlayingField implements Serializable {
	
	/**
	 * serialVersionUID for the PlayingField class
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Multidimensional array representing the tiles with Colors
	 */
	private Color[][] tiles = 
			new Color[Numbers.TWENTY_TWO.getNumber()][Numbers.TEN.getNumber()];
	
	/**
	 * current level
	 */
	private int level = 1;
	
	/**
	 * current score
	 */
	private int score;
	
	/**
	 * current combo count
	 */
	private int comboCount;
	
	/** for TWO **/
	private static final int TWO = 2;
	
	/** for THREE **/
	private static final int THREE = 3;
	
	/** for FOUR **/
	private static final int FOUR = 4;
	
	/**
	 * This method checks and changes the level depending on the score.
	 * (it goes up one level every 10000 points)
	 */
	public void changeLevel() {
		level = score / Numbers.TEN_THOUSAND.getNumber() + 1;
		return;
	}
	
	/**
	 * This method checks and clears any line (one or more)
	 *  that should be cleared (full lines), 
	 * and also calculates and add scores
	 *  (depending on the level and the combo count).
	 * (this method gives bonus both when multiple lines
	 *  are cleared at the same time, 
	 * and/or when a player cleared line(s)
	 *  in a row (weighted differently). 
	 * The instance variable comboCount and the class
	 *  variable comboCount represents different values) 
	 */
	public void checkForClears() {
		int comboCount = 0;
		for (int i = 0; i < Numbers.TWENTY_TWO.getNumber(); i++) {
			boolean check = true;
			for (int j = 0; j < Numbers.TEN.getNumber(); j++) {
				if (tiles[i][j] == null || tiles[i][j].equals(Color.GRAY)
						|| tiles[i][j].equals(Color.PINK)) {
					check = false;
				}
			}
			if (check) {
				for (int k = 0; k < Numbers.TEN.getNumber(); k++) {
					tiles[i][k] = null;
				}
				int count = 0;
				for (int a = i; a > 0; a--) {
					while (count < Numbers.TEN.getNumber()) {
						tiles[a][count] = tiles[a - 1][count];
						count++;
					}
					/*
					for (int b = zero; b < ten; b++) {
						tiles[a][b] = tiles[a - 1][b];
					}
					*/
				}
				comboCount++;
			}
		}
		this.calcComboCount(comboCount);
	}
	
	/**
	 * to count combo count
	 * @param comboCount
	 */
	private void calcComboCount(int comboCount) {
		switch (comboCount) {
			case FOUR:
				score += level * Numbers.TWELVE_HUNDRED.getNumber() 
				+ Numbers.FIVE_HUNDRED.getNumber() * this.comboCount;
				this.comboCount++;
				break;
			case THREE:
				score += level * Numbers.THREE_HUNDRED.getNumber() 
				+ Numbers.FIVE_HUNDRED.getNumber() * this.comboCount;
				this.comboCount++;
				break;
			case TWO:
				score += level * Numbers.HUNDRED.getNumber() 
				+ Numbers.FIVE_HUNDRED.getNumber() * this.comboCount;
				this.comboCount++;
				break;
			case 1:
				score += level * Numbers.FORTY.getNumber() 
				+ Numbers.FIVE_HUNDRED.getNumber() * this.comboCount;
				this.comboCount++;
				break;
			case 0:
				this.comboCount = 1;
				break;
			default:
				break;
		}
	}
	
	/**
	 * This method checks if a loss condition has met, 
	 * which means one or more of the block(s) has 
	 * reached the top first row of the board. 
	 * 
	 * @return true if the loss condition has met, false otherwise
	 */
	public boolean isLossConditionMet() {
		for (int i = 0; i < Numbers.TEN.getNumber(); i++) {
			if (tiles[0][i] != null) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * This method checks if a tile is vacant for
	 *  the corresponding x and y position in tiles. 
	 * 
	 * @param x The column number of the tile to be checked
	 * @param y The row number of the tile to be checked
	 * @return true if the tile is vacant, false otherwise
	 */
	public boolean isTileVacant(int x, int y) {
		if (x >= Numbers.TEN.getNumber() 
				|| y > Numbers.TWENTY_ONE.getNumber() || x < 0 || y < -1) {
			return false;
		} else if (y == -1) {
			return true;
		} else if (tiles[y][x] == null) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * This method fills the tile in for the corresponding x and y position in tiles. 
	 * 
	 * @param x The column number of the tile to be checked
	 * @param y The row number of the tile to be checked 
	 * @param color The Color to be filled in
	 */
	public void fillTile(int x, int y, Color color) {
		tiles[y][x] = color;
	}
	
	/**
	 * This method draws the representation of the field to the main Tetris board. 
	 * 
	 * @param g The Graphics object for the pieces to be drawn on
	 * @param tileDimension The current tileDimension that the tiles should be drawn with
	 */
	public void draw(Graphics g, Dimension tileDimension) {
		for (int i = 0; i < Numbers.TWENTY_TWO.getNumber(); i++) {
			for (int j = 0; j < Numbers.TEN.getNumber(); j++) {
				if (tiles[i][j] != null) {
					g.setColor(tiles[i][j]);
					g.fillRect(j * tileDimension.width, i *
							tileDimension.height, tileDimension.width,
							tileDimension.height);
				}
			}
		}
	}
	
	/**
	 * This is a getter for the current score. 
	 * 
	 * @return The current score
	 */
	public int getScore() {
		return score;
	}
	
	/**
	 * This is a getter for the current level. 
	 * 
	 * @return The current level
	 */
	public int getLevel() {
		return level;
	}
	
	/**
	 * This is a setter for the current score. 
	 * 
	 * @param score The score to be set to
	 */
	public void setScore(int score) {
		this.score = score;
	}
	
	/**
	 * This is a setter for the current level. 
	 * 
	 * @param level The level to be set to
	 */
	public void setLevel(int level) {
		this.level = level;
	}
	
	/**
	 * Reset the field
	 */
	public void resetField() {
		tiles = new Color[Numbers.TWENTY_TWO.getNumber()][Numbers.TEN.getNumber()];
		level = 1;
		score = 0;
		comboCount = 0;
	}

	/** 
	 * This is a tostring method.
	 * @return tostring.
	 */
	@Override
	public String toString() {
		return super.toString();
	}
}
